<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Controller\admin;

use App\Controller\admin\common\Util;
use App\Exception\BusinessException;
use App\Model\Admin\Admin;
use Hyperf\HttpServer\Contract\RequestInterface;
use Psr\Http\Message\ResponseInterface;

use function Ella123\HyperfCaptcha\captcha_verify;
use function Hyperf\Config\config;
use Hyperf\DbConnection\Model\Model;
/**
 * 管理员账户.
 */

class AccountController extends Crud
{
    /**
     * 不需要登录的方法.
     * @var string[]
     */
    protected array $noNeedLogin = ['login', 'logout', 'captcha'];

    /**
     * 不需要鉴权的方法.
     * @var string[]
     */
    protected array $noNeedAuth = ['info'];

    /**
     * @var Admin
     */
    protected Model $model;

    /**
     * 构造函数.
     */
    public function __construct()
    {
        $this->model = new Admin();
        parent::__construct();
    }

    /**
     * 账户设置.
     */
    public function index(): ResponseInterface
    {
        return $this->render->render('account/index');
    }

    /**
     * 登录.
     */
    public function login(): ResponseInterface
    {
        $this->checkDatabaseAvailable();
        $captcha = $this->request->post('captcha', '');
        //验证码验证有点问题
        $captcha_verify = captcha_verify('login',$captcha);
        if ($captcha_verify==false) {
            return $this->json(1, '验证码错误');
        }
        $username = $this->request->post('username', '');
        $password = $this->request->post('password', '');
        if (!$username) {
            return $this->json(1, '用户名不能为空');
        }
        $this->checkLoginLimit($username);
        $admin = Admin::where('username', $username)->first();
        if (! $admin || ! Util::passwordVerify($password, $admin->password)) {
            return $this->json(1, '账户不存在或密码错误');
        }
        if ($admin->status != 0) {
            return $this->json(1, '当前账户暂时无法登录');
        }
        $admin->login_at = date('Y-m-d H:i:s');
        $admin->save();
        $this->removeLoginLimit($username);
        $admin = $admin->toArray();
        $session = $this->session;
        $admin['password'] = md5($admin['password']);
        $session->set('admin', $admin);
        return $this->json(0, '登录成功', [
            'nickname' => $admin['nickname'],
            'token' => $session->getId(),
        ]);
    }

    /**
     * 退出.
     */
    public function logout(): ResponseInterface
    {
        $this->session->forget('admin');
        return $this->json(0);
    }

    /**
     * 获取登录信息.
     */
    public function info(): ResponseInterface
    {
        $admin = admin();
        if (!$admin) {
            return $this->json(1);
        }
        $info = [
            'id' => $admin['id'],
            'username' => $admin['username'],
            'nickname' => $admin['nickname'],
            'avatar' => $admin['avatar'],
            'email' => $admin['email'],
            'mobile' => $admin['mobile'],
            'isSuperAdmin' => (new common\Auth)->isSuperAdmin(),
            'token' => $this->session->getId(),
        ];
        return $this->json(0, 'ok', $info);
    }

    /**
     * 更新.
     */
    public function update(): ResponseInterface
    {
        $allow_column = [
            'nickname' => 'nickname',
            'avatar' => 'avatar',
            'email' => 'email',
            'mobile' => 'mobile',
        ];

        $data = $this->request->all();
        $update_data = [];
        foreach ($allow_column as $key => $column) {
            if (isset($data[$key])) {
                $update_data[$column] = $data[$key];
            }
        }
        if (isset($update_data['password'])) {
            $update_data['password'] = Util::passwordHash($update_data['password']);
        }
        Admin::where('id', admin_id())->update($update_data);
        $admin = admin();
        unset($update_data['password']);
        foreach ($update_data as $key => $value) {
            $admin[$key] = $value;
        }
        $this->session->set('admin', $admin);
        return $this->json(0);
    }

    /**
     * 修改密码
     */
    public function password(RequestInterface $request): ResponseInterface
    {
        $hash = Admin::find(admin_id())['password'];
        $password = $request->post('password');
        if (! $password) {
            return $this->json(2, '密码不能为空');
        }
        if ($request->post('password_confirm') !== $password) {
            return $this->json(3, '两次密码输入不一致');
        }
        if (! Util::passwordVerify($request->post('old_password'), $hash)) {
            return $this->json(1, '原始密码不正确');
        }
        $update_data = [
            'password' => Util::passwordHash($password),
        ];
        Admin::where('id', admin_id())->update($update_data);
        return $this->json(0);
    }

    /**
     * 验证码
     */
    public function captcha(): ResponseInterface
    {
        $type = $this->request->input('type', 'login');
        # 创建图片验证码
        $data = \Ella123\HyperfCaptcha\captcha_create($type);
        $key = $data['key']; # 验证码标识
        $img = $data['img']; # 验证码图片
        # 验证图片验证码
        # $code: 用户输入的验证码
        # $key: 创建验证码的时候返回的key
        //\Ella123\HyperfCaptcha\captcha_verify($code,$key);
        return $this->response->raw($img);
    }

    /**
     * 检查登录频率限制.
     * @throws BusinessException
     */
    protected function checkLoginLimit(mixed $username): void
    {
        $limit_log_path = BASE_PATH . '/runtime/login';
        if (! is_dir($limit_log_path)) {
            mkdir($limit_log_path, 0777, true);
        }
        $limit_file = $limit_log_path . '/' . md5($username) . '.limit';
        $time = date('YmdH') . ceil(date('i') / 5);
        $limit_info = [];
        if (is_file($limit_file)) {
            $json_str = file_get_contents($limit_file);
            $limit_info = json_decode($json_str, true);
        }

        if (! $limit_info || $limit_info['time'] != $time) {
            $limit_info = [
                'username' => $username,
                'count' => 0,
                'time' => $time,
            ];
        }
        ++$limit_info['count'];
        file_put_contents($limit_file, json_encode($limit_info));
        if ($limit_info['count'] >= 5) {
            throw new BusinessException(500, '登录失败次数过多，请5分钟后再试');
        }
    }

    /**
     * 解除登录频率限制.
     */
    protected function removeLoginLimit(mixed $username): void
    {
        $limit_log_path = BASE_PATH . '/runtime/login';
        $limit_file = $limit_log_path . '/' . md5($username) . '.limit';
        if (is_file($limit_file)) {
            unlink($limit_file);
        }
    }

    protected function checkDatabaseAvailable(): void
    {
        if (!config('databases')) {
            throw new BusinessException(500, '请重启hyperf');
        }
    }
}
